package com.yenlien.traceyun.business.service;

import com.alibaba.fastjson.JSONObject;
import com.yenlien.traceyun.business.bean.OrderSearch;
import com.yenlien.traceyun.business.controller.response.ClientOrderView;
import com.yenlien.traceyun.business.dao.*;
import com.yenlien.traceyun.business.entity.*;
import com.yenlien.traceyun.business.interceptor.UserAuthUtil;
import com.yenlien.traceyun.common.utils.DateUtil;
import com.yenlien.traceyun.common.utils.RandomUtil;
import com.yenlien.traceyun.common.utils.Tools;
import com.yenlien.traceyun.webase.exception.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: bigwangy@sina.com
 * @create: 2020-12-08
 * @description:
 **/

@Service
public class ClientOrderService {

    @Autowired
    private ClientOrderDao clientOrderDao;

    @Autowired
    private ClientOrderDetailDao clientOrderDetailDao;

    @Autowired
    private InvoiceDao invoiceDao;

    @Autowired
    private PayRecordDao payRecordDao;

    @Value("${traceyun.app.id}")
    private String appId;

    @Autowired
    private StorageManageDao storageManageDao;

    /**
     * 保存订单
     *
     * @param order
     * @param detaileds
     * @param invoice
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public ClientOrder save(ClientOrder order, List<ClientOrderDetailed> detaileds, Invoice invoice) {
        if (detaileds == null || detaileds.size() == 0) {
            throw new BusinessException("500", "订单没有明细数据");
        }
        //添加
        if (StringUtils.isEmpty(order.getId())) {
            order.setOrderNo(Tools.getDateAll() + RandomUtil.randomNum(4));
            String companyId = UserAuthUtil.getLoginUser().getCompanyId();
            order.setCompanyId(companyId);
            invoiceDao.save(invoice);
            order.setInvoiceId(invoice.getId());
            order.setAppId(appId);
            ClientOrder p = clientOrderDao.save(order);

            for (ClientOrderDetailed detailed : detaileds) {
                detailed.setOrderId(p.getId());
                detailed.setClientName(p.getClientName());
                detailed.setCreatetime(p.getCreatetime());
            }
            List<String> stroageIds = detaileds.stream().map(p1 -> p1.getRelateId()).collect(Collectors.toList());
            storageManageDao.updateOutNumByIds(stroageIds, 1);
            clientOrderDetailDao.saveAll(detaileds);

        } else {
            invoiceDao.save(invoice);
            List<ClientOrderDetailed> detailedList = clientOrderDetailDao.findByOrderId(order.getId());
            List<String> oldstoreageIds = detailedList.stream().map(p -> p.getRelateId()).collect(Collectors.toList());
            storageManageDao.updateOutNumByIds(oldstoreageIds, -1);
            clientOrderDetailDao.deleteByOrderId(order.getId());

            for (ClientOrderDetailed detailed : detaileds) {
                detailed.setOrderId(order.getId());
                detailed.setClientName(order.getClientName());
            }
            List<String> stroageIds = detaileds.stream().map(p -> p.getRelateId()).collect(Collectors.toList());
            storageManageDao.updateOutNumByIds(stroageIds, 1);
            clientOrderDetailDao.saveAll(detaileds);
            String companyId = UserAuthUtil.getLoginUser().getCompanyId();
            order.setCompanyId(companyId);
            order.setAppId(appId);
            order.setCreatetime(new Date());
            order.setInvoiceId(invoice.getId());
            clientOrderDao.save(order);
        }
        return order;
    }

    /**
     * 删除订单
     *
     * @param orderId
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void del(String orderId) {
        ClientOrder order = clientOrderDao.findById(orderId).get();
        if (order.getInvoiceId() != 0) {
            invoiceDao.deleteById(order.getInvoiceId());
        }
        clientOrderDao.delete(order);
        clientOrderDetailDao.deleteByOrderId(orderId);
    }

    /**
     * 根据id加载
     *
     * @param orderId
     * @return
     */
    public Object load(String orderId) {
        JSONObject data = new JSONObject();
        ClientOrder order = clientOrderDao.findById(orderId).get();
        data.put("order", order);
        data.put("details", clientOrderDetailDao.findByOrderId(orderId));
        if (order.getInvoiceId() != 0) {
            data.put("invoice", invoiceDao.findById(order.getInvoiceId()).get());
        } else {
            data.put("invoice", null);
        }
        return data;
    }

    /**
     * 付款
     *
     * @param payRecord
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public Object pay(PayRecord payRecord) {
        ClientOrder order = clientOrderDao.findById(payRecord.getOrderId()).get();
        order.setPayAmount(order.getPayAmount().add(payRecord.getCash()));
        if (order.getPayAmount().compareTo(order.getTotalAmount()) > 0) {
            throw new BusinessException("500", "大于应收总金额");
        }
        order.setPayType(payRecord.getPayType());
        payRecordDao.save(payRecord);
        return payRecord;
    }

    public Page<ClientOrder> findpage(OrderSearch search) {
        search.setAppId(appId);
        Pageable pageable = PageRequest.of(search.getPageno() == -1 ? 0 : search.getPageno(), search.getPagesize(), Sort.Direction.DESC, "createtime");
        return clientOrderDao.findAll(create(search), pageable);
    }

    public Specification create(OrderSearch search) {
        return (Specification<ClientOrder>) (root, query, cb) -> {
            //构造查询条件
            List<Predicate> list = new ArrayList<>();
            if (!StringUtils.isEmpty(search.getCompanyId())) {
                list.add(cb.equal(root.get("companyId"), search.getCompanyId()));
            }
            if (!StringUtils.isEmpty(search.getAppId())) {
                list.add(cb.equal(root.get("appId"), search.getAppId()));
            }
            if (!StringUtils.isEmpty(search.getStarttime())) {
                list.add(cb.greaterThanOrEqualTo(root.get("createtime"), DateUtil.toDay(search.getStarttime())));
            }
            if (!StringUtils.isEmpty(search.getEndtime())) {
                list.add(cb.lessThan(root.get("createtime"), DateUtil.toDay(search.getEndtime())));
            }
            if (!StringUtils.isEmpty(search.getRelateId())) {
                list.add(cb.equal(root.get("clientId"), search.getRelateId()));
            }
            if (!StringUtils.isEmpty(search.getDeliverState())) {
                list.add(cb.equal(root.get("deliverState"), search.getDeliverState()));
            }
            if (!StringUtils.isEmpty(search.getPayState())) {
                list.add(cb.equal(root.get("payState"), search.getPayState()));
            }
            if (search.getIds() != null && search.getIds().size() > 0) {
                CriteriaBuilder.In<Object> in = cb.in(root.get("id"));
                for (String id : search.getIds()) {
                    in.value(id);
                }
                list.add(in);
            }
            Predicate[] predicate = new Predicate[list.size()];
            Predicate pre_and = cb.and(list.toArray(predicate));
            return pre_and;
        };
    }

    /**
     * 列表详情展示
     *
     * @param search
     * @return
     */
    public List<ClientOrderView> listPage(OrderSearch search) {
        search.setCompanyId(UserAuthUtil.getLoginUser().getCompanyId());
        search.setAppId(appId);
        List<ClientOrderView> views = new ArrayList<>();
        Page<ClientOrder> orders = findpage(search);
        List<String> orderIds = orders.getContent().stream().map(p -> p.getId()).collect(Collectors.toList());
        if (orderIds != null) {

            List<ClientOrderDetailed> clientOrderDetaileds = clientOrderDetailDao.findByOrderIdIn(orderIds);
            for (ClientOrder order : orders) {
                ClientOrderView view = new ClientOrderView(order);
                view.setDetaileds(getDetails(order, clientOrderDetaileds));
                views.add(view);
            }
        }
        return views;
    }

    public Page<ClientOrderDetailed> getClientOrderDetail(OrderSearch search) {
        List<ClientOrder> orders = clientOrderDao.findByClientId(search.getRelateId());
        List<String> orderIds = orders.stream().map(p -> p.getId()).collect(Collectors.toList());
        if (orderIds != null) {
            Pageable pageable = PageRequest.of(search.getPageno() == -1 ? 0 : search.getPageno(), search.getPagesize(), Sort.Direction.DESC, "createtime");
            return clientOrderDetailDao.findByOrderIdIn(orderIds, pageable);
        }
        return null;

    }

    /**
     * 获取订单明细
     *
     * @param order
     * @param clientOrderDetaileds
     * @return
     */
    private List<ClientOrderDetailed> getDetails(ClientOrder order, List<ClientOrderDetailed> clientOrderDetaileds) {
        List<ClientOrderDetailed> result = new ArrayList<>();
        if (clientOrderDetaileds != null && clientOrderDetaileds.size() > 0) {
            Iterator<ClientOrderDetailed> iterator = clientOrderDetaileds.iterator();
            while (iterator.hasNext()) {
                ClientOrderDetailed detailed = iterator.next();
                if (detailed.getOrderId().equals(order.getId())) {
                    result.add(detailed);
                    iterator.remove();
                }
            }
        }
        return result;
    }

    /**
     * 根据库存获取需要出库的订单
     *
     * @param search
     * @return
     */
    public Page<ClientOrder> pageByStorageId(OrderSearch search) {
        List<ClientOrderDetailed> detaileds = clientOrderDetailDao.findByRelateIdAndIsOut(search.getRelateId(), false);
        Set<String> orderIds = detaileds.stream().map(p -> p.getOrderId()).collect(Collectors.toSet());
        List<String> ids = new ArrayList<>(orderIds);
        search.setIds(ids);
        search.setRelateId("");
        return findpage(search);
    }
}
